// $Id: //CBT-depot/CBT++/src/SpeciesVerificationHashEntry.cc#1 $

// The include list goes here.
#include "SpeciesVerificationHashEntry.hh"

int main(){
  if ((sizeof(Word) != 8) || (sizeof(unsigned int) != 4)){
    ostringstream reason;
    reason << "Your platform is not supported.\n";
    reason << "This program requires that an unsigned int be 32 bits and\n";
    reason << "an unsigned long long be 64 bits." << endl;
    throw PlatformUnsupportedException(reason.str());
  }
  SpeciesVerificationHashEntry blueprint;
  Extension* ve;
  Extension* ve2;
  Extension* ve3;
  Extension* ve4;
  HashRecord good(123456789, NULL); 
  HashRecord good2(852533108, NULL); 
  HashRecord good3(352149512, NULL); 
  HashRecord good4(905685445, NULL);
  Extension* badVector = new Extension[1];
  badVector[0] = 212;
  HashRecord bad(4, badVector);
  SpeciesVerificationHashEntry* hv = dynamic_cast<SpeciesVerificationHashEntry*>(blueprint.typedValue(good));
  SpeciesVerificationHashEntry* hv2 = dynamic_cast<SpeciesVerificationHashEntry*>(blueprint.typedValue(good2));
  SpeciesVerificationHashEntry* hv3 = dynamic_cast<SpeciesVerificationHashEntry*>(blueprint.typedValue(good3));
  SpeciesVerificationHashEntry* hv4 = dynamic_cast<SpeciesVerificationHashEntry*>(blueprint.typedValue(good4));

  HashRecord cb = hv->integerValues();
  cout << "The size is " << (1 + hv->numberOfExtensions()) << "." << endl;
  cout << good.primaryRecord << " = " << cb.primaryRecord << endl;
  cout << "String representation: " << hv->toString() << endl;
  Word hk = hv->hashKey();
  HashRecord test(hk, NULL);
  SpeciesVerificationHashEntry* testHV = dynamic_cast<SpeciesVerificationHashEntry*>(blueprint.typedValue(test));
  cout << "Hash key: " << hk << endl;
  cout << "String representation of hash key: " << testHV->toString() << endl;
  //HashFiller* hf2 = new HashFiller(4294967295U, 7, hv);
  HashFiller* hf2;
  try{
    hf2 = new HashFiller(2147483648U, 7, hv);
    delete hf2;
  }
  catch (exception &e){
    cout << e.what();
  }
  if (DEBUG){
    cout << "Creating new hash of three elements..." << endl;
  }
  HashFiller* hf = new HashFiller(3, hv);  // default hash-thinning prime = 1
  if (DEBUG){
    cout << "Hash created; searching..." << endl;
    cout << "Hash after creation:" << endl;
    hf->printHash();
    cout << "Before searching, hash size = " << hf->hashSize << endl;
  }
  Index location = hf->lookUp(hv);
  if (DEBUG){
    cout << "Finished searching!" << endl;
    cout << "After searching, hash size = " << hf->hashSize << endl;
  }
  if (location == NOT_FOUND_IN_HASH){
    cout << hv->bases() << " was not found." << endl;
  }
  else{
    cout << hv->bases() << " was found at " << location << endl;
  }
  try{
    cout << "Hash before insertion: " << endl;
    hf->printHash();
    hf->insertEntry(hv);
    cout << "Hash after insertion: " << endl;
    hf->printHash();
    cout << "After one insertion: " << hv->toString() << endl;
    cout << "Found at " << hf->lookUp(hv) << "!" << endl;
    cout << "Before second insertion: " << hv2->toString() << endl;
    hf->insertEntry(hv2);
    cout << "After two insertions: " << hv2->toString() << endl;
    cout << "Found at " << hf->lookUp(hv) << "!" << endl;
    cout << "Found at " << hf->lookUp(hv2) << "!" << endl;
    cout << "Before third insertion: " << hv3->toString() << endl;
    hf->insertEntry(hv3);
    cout << "After three insertions: " << hv3->toString() << endl;
    cout << "Found at " << hf->lookUp(hv) << "!" << endl;
    cout << "Found at " << hf->lookUp(hv2) << "!" << endl;
    cout << "Found at " << hf->lookUp(hv3) << "!" << endl;
    cout << "Before fourth insertion: " << hv4->toString() << endl;
    hf->insertEntry(hv4);
    cout << "After four insertions: " << hv4->toString() << endl;
    cout << "Found at " << hf->lookUp(hv) << "!" << endl;
    cout << "Found at " << hf->lookUp(hv2) << "!" << endl;
    cout << "Found at " << hf->lookUp(hv3) << "!" << endl;
    cout << "Found at " << hf->lookUp(hv4) << "!" << endl;
  }
  catch (HashFullException &hfe){
    cout << hfe.what();
  }
  // Always delete the hash before deleting its blueprint.
  delete hf;
  delete hv;
  delete hv2;
  delete hv3;
  delete hv4;
  delete testHV;
  hv = dynamic_cast<SpeciesVerificationHashEntry*>(blueprint.typedValue(bad));
  if (hv){
    cout << "An array of size two was incorrectly accepted." << endl;
    delete hv;
  }
  else{
    cout << "An array of size two was correctly rejected." << endl;
  }
  delete[] badVector;
  return 0;
}

